#include "logan_queue.h"
#include "clogan_core.h"
#include <cstring>
#include <ctime>
#include <iostream>
#include <thread>  // 添加线程相关头文件
#include <dirent.h>   // 添加目录操作头文件
#include <cstdlib>    // 添加字符串转数字函数头文件

LoganQueue &LoganQueue::getInstance() {
    static LoganQueue instance;
    return instance;
}

LoganQueue::LoganQueue()
    : writer_running_(false), max_queue_size_(0), timezone_offset_ms_(0), save_time_(MS_PER_DAY * 7), log_dir_path_(nullptr),main_thread_id_(0) {}

LoganQueue::~LoganQueue() { 
    stopWriterThread(); 
    
    // 释放日志目录路径内存
    if (log_dir_path_) {
        free(log_dir_path_);
        log_dir_path_ = nullptr;
    }
}

void LoganQueue::init(int max_queue_size, int save_time, const char* path_path) {
    max_queue_size_ = max_queue_size;
    save_time_ = save_time;
    if (log_dir_path_) {
        free(log_dir_path_);
        log_dir_path_ = nullptr;
    }
    
    if (path_path) {
        log_dir_path_ = strdup(path_path);
    }
    
    // 保存主线程ID
    main_thread_id_ = static_cast<long long>(std::hash<std::thread::id>{}(std::this_thread::get_id()));
}

void LoganQueue::registerJSLoganCallback(const JSLoganCallback& callback) {
    js_callback_ = callback;
}

void LoganQueue::callJSLoganCallback(const std::string& cmd, int code) {
    if (js_callback_) {
        js_callback_(cmd, code);
    }
}

bool LoganQueue::addLogWrite(int flag, const char *log, long long local_time, const char *thread_name,
                             long long thread_id) {
    if(max_queue_size_ == 0){
        return false;
    }
    // 创建日志操作
    log_operation_t operation;
    operation.type = LOG_OPERATION_WRITE;

    // 复制数据
    operation.data.flag = flag;
    operation.data.local_time = local_time;
    operation.data.thread_id = thread_id;
    
    // 判断是否为主线程
    operation.data.is_main = (thread_id == main_thread_id_) ? 1 : 0;

    // 复制字符串数据
    operation.data.log = log ? strdup(log) : nullptr;
    operation.data.thread_name = thread_name ? strdup(thread_name) : nullptr;

    {
        std::lock_guard<std::mutex> lock(queue_mutex_);

        // 如果队列已满，丢弃最旧的操作
        if (log_queue_.size() >= static_cast<size_t>(max_queue_size_)) {

            // 移除最旧的操作并释放内存
            log_operation_t old_operation = log_queue_.front();
            log_queue_.pop();
            freeOperation(old_operation);
        }

        // 添加新操作到队列
        log_queue_.push(operation);
    }

    // 通知写入线程有新数据
    queue_cv_.notify_one();

    return true;
}

bool LoganQueue::addLogFlush() {
    if(max_queue_size_ == 0){
        return false;
    }
    // 创建刷新操作
    log_operation_t operation;
    operation.type = LOG_OPERATION_FLUSH;

    // 初始化数据部分（对于flush操作不需要数据）
    memset(&operation.data, 0, sizeof(operation.data));

    {
        std::lock_guard<std::mutex> lock(queue_mutex_);

        // 如果队列已满，丢弃最旧的操作
        if (log_queue_.size() >= static_cast<size_t>(max_queue_size_)) {

            // 移除最旧的操作并释放内存
            log_operation_t old_operation = log_queue_.front();
            log_queue_.pop();
            freeOperation(old_operation);
        }

        // 添加新操作到队列
        log_queue_.push(operation);
    }

    // 通知写入线程有新数据
    queue_cv_.notify_one();

    return true;
}

void LoganQueue::startWriterThread() {
    if (writer_running_) {
        return;
    }

    writer_running_ = true;
    writer_thread_ = std::make_unique<std::thread>(&LoganQueue::writerThreadMain, this);
}

void LoganQueue::stopWriterThread() {
    if (!writer_running_) {
        return;
    }

    writer_running_ = false;
    queue_cv_.notify_all();

    if (writer_thread_ && writer_thread_->joinable()) {
        writer_thread_->join();
    }

    // 清空队列中剩余的操作
    std::lock_guard<std::mutex> lock(queue_mutex_);
    while (!log_queue_.empty()) {
        log_operation_t operation = log_queue_.front();
        log_queue_.pop();
        freeOperation(operation);
    }
}

void LoganQueue::writerThreadMain() {

    // 在启动写入线程时计算一次时区偏移量
    timezone_offset_ms_ = calculateTimezoneOffset();

    while (writer_running_) {
        std::unique_lock<std::mutex> lock(queue_mutex_);

        // 等待队列中有数据或者线程停止
        queue_cv_.wait(lock, [this] { return !log_queue_.empty() || !writer_running_; });

        // 处理队列中的所有操作
        while (!log_queue_.empty() && writer_running_) {
            log_operation_t operation = log_queue_.front();
            log_queue_.pop();
            lock.unlock();

            // 实际处理操作
            processOperation(operation);

            // 释放内存
            freeOperation(operation);

            lock.lock();
        }
    }
}

void LoganQueue::processOperation(const log_operation_t &operation) {
    switch (operation.type) {
    case LOG_OPERATION_WRITE:
        writeLog(operation.data);
        break;
    case LOG_OPERATION_FLUSH:
        flushLog();
        break;
    default:
        break;
    }
}

void LoganQueue::writeLog(const log_entry_data_t &entry) {
    // 检查是否需要打开新的日志文件（基于日期变化，考虑时区）
    static long last_day = 0;

    // 使用预先计算好的时区偏移量
    long local_time_with_timezone = entry.local_time + timezone_offset_ms_;
    long current_day = local_time_with_timezone / MS_PER_DAY; // 转换为天数

    if (current_day > last_day) {
        // 日期已经变化，需要打开新的日志文件
        long current_day_time = current_day * MS_PER_DAY - timezone_offset_ms_;
        // save时间
        long deleteTime = current_day_time - save_time_;
        // 删除过期文件
        deleteExpiredFile(deleteTime);

        // 按照原来格式只使用时间戳
        char pathname[64];
        snprintf(pathname, sizeof(pathname), "%ld", current_day_time);
        int result = clogan_open(pathname);
        
        // 调用JS回调函数
        callJSLoganCallback("clogan_open", result);

        last_day = current_day;
    }

    // 调用原有的clogan_write函数进行实际的日志写入
    int result = clogan_write(entry.flag, entry.log, entry.local_time, entry.thread_name, entry.thread_id, entry.is_main);
    
    // 调用JS回调函数
    callJSLoganCallback("clogan_write", result);
}

void LoganQueue::flushLog() {
    // 调用原有的clogan_flush函数进行日志刷新
    int result = clogan_flush();
    
    // 调用JS回调函数
    callJSLoganCallback("clogan_flush", result);
}

void LoganQueue::freeOperation(log_operation_t &operation) {
    // 只有写入操作需要释放字符串内存
    if (operation.type == LOG_OPERATION_WRITE) {
        if (operation.data.log) {
            free(operation.data.log);
            operation.data.log = nullptr;
        }

        if (operation.data.thread_name) {
            free(operation.data.thread_name);
            operation.data.thread_name = nullptr;
        }
    }
}

void LoganQueue::setDebug(int debug) { clogan_debug(debug); }

long LoganQueue::calculateTimezoneOffset() {
    // 获取当前时间
    time_t rawtime;
    time(&rawtime);

    // 获取UTC时间和本地时间
    struct tm utc_tm, local_tm;
    gmtime_r(&rawtime, &utc_tm);
    localtime_r(&rawtime, &local_tm);

    // 计算时区偏移（以毫秒为单位）
    long offset_seconds = (local_tm.tm_hour - utc_tm.tm_hour) * 3600 + (local_tm.tm_min - utc_tm.tm_min) * 60;

    // 考虑日期变化的情况
    int day_diff = local_tm.tm_mday - utc_tm.tm_mday;
    int month_diff = local_tm.tm_mon - utc_tm.tm_mon;
    int year_diff = local_tm.tm_year - utc_tm.tm_year;

    if (day_diff != 0 || month_diff != 0 || year_diff != 0) {
        // 如果日期不同，需要调整时区偏移
        offset_seconds += day_diff * 24 * 3600;
    }

    return offset_seconds * 1000; // 转换为毫秒
}

// 删除过期文件的实现
void LoganQueue::deleteExpiredFile(long long deleteTime) {
    if (log_dir_path_ == nullptr) {
        return;
    }
    
    DIR *dir = opendir(log_dir_path_);
    if (dir == nullptr) {
        return;
    }
    
    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr) {
        // 跳过目录项 "." 和 ".."
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        
        try {
            // 检查文件名是否为空
            if (strlen(entry->d_name) == 0) {
                continue;
            }
            
            // 查找文件名中的点号位置
            char *dot_position = strchr(entry->d_name, '.');
            long long file_time = 0;
            
            if (dot_position != nullptr) {
                // 如果有点号，只取点号前的部分
                size_t prefix_len = dot_position - entry->d_name;
                if (prefix_len > 0) {
                    char *prefix = strndup(entry->d_name, prefix_len);
                    file_time = strtoll(prefix, nullptr, 10);
                    free(prefix);
                }
            } else {
                // 如果没有点号，整个文件名就是时间戳
                file_time = strtoll(entry->d_name, nullptr, 10);
            }
            
            // 判断文件时间是否小于等于删除时间
            if (file_time > 0 && file_time <= deleteTime) {
                // 构造完整文件路径
                size_t path_len = strlen(log_dir_path_) + strlen(entry->d_name) + 2; // +2 for '/' and '\0'
                char *file_path = (char *)malloc(path_len);
                if (file_path != nullptr) {
                    snprintf(file_path, path_len, "%s/%s", log_dir_path_, entry->d_name);
                    // 删除文件
                    remove(file_path);
                    free(file_path);
                }
            }
        } catch (...) {
        }
    }
    
    closedir(dir);
}
